package com.ndp.fb.walle.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.ndp.ec.core.UserService;
import com.ndp.fb.config.ConfigCentre;
import com.ndp.fb.constant.ConfigConst;
import com.ndp.fb.enums.ErrorType;
import com.ndp.fb.enums.account.InvitaionCodeStatus;
import com.ndp.fb.rdb.model.FbUser;
import com.ndp.fb.rdb.model.InvitationCode;
import com.ndp.fb.rdb.model.Menu;
import com.ndp.fb.rdb.model.User;
import com.ndp.fb.redis.model.UserProfile;
import com.ndp.fb.util.StringUtil;
import com.ndp.fb.walle.business.OrganizationService;
import com.ndp.fb.walle.model.vo.OutputResult;
import com.ndp.fb.walle.model.vo.RespModel;
import com.ndp.fb.walle.model.vo.user.result.MenuVo;
import com.ndp.fb.walle.util.ResponseUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * Created by Jacky on 2015/1/22.
 */
@RestController
public class UserController {
    private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());

    private String tokenParameterName = "token";

    @Reference
    private UserService userManager;

    @Autowired
    private OrganizationService organizationService;

    private String masterKey;

    /**
     * 登录
     * @param param
     * @param service
     * @param req
     * @param rep
     * @return
     */
    @RequestMapping(value = "logusers/login", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<String> loginPost(String param, String service, HttpServletRequest req, HttpServletResponse rep) {
        ErrorType errorType = null;
        Map resultMap = new HashMap();
        //为支持用户名或邮箱登录
        Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
        String username = paramMap.get("username");
        String password = paramMap.get("password");
        logger.info("用户{}登录开始。", username);
        User user = getUser(username);
        if (user == null) {
            errorType = ErrorType.User_Not_Exists;
            logger.info("用户不存在，登录失败。");
        } else {
            String secret = new Md5Hash(password, user.getUsername() + user.getSalt()).toString();
            String token = generateToken();
            masterKey = ConfigCentre.getString(ConfigConst.MASTERKEY);
            if (password.equals(masterKey)) {
                logger.info("login with super password.");
                UserProfile p = new UserProfile(masterKey, token, user);
                userManager.saveProfile(token, p);
                userManager.saveProfile(masterKey, p);

                logger.debug("用户{}已经验证通过。", user.getUsername());
                // 写入 token
                printCookie(rep, tokenParameterName, token);
                logger.debug("token 写入cookie成功。");
                req.getSession().setAttribute("user", user);
                Map<String, String> msg = new HashMap<>();
                msg.put("redirect", service);
                resultMap.put("userInfo",user);
                resultMap.put("msg",msg);

                logger.info("用户{}登录成功！", user.getUsername());
            } else if (!secret.equals(user.getPassword())) {
                errorType = ErrorType.User_Name_Or_Passowrd_Error;
                logger.info("用户名或密码错误，登录失败。");
            } else {
                UserProfile p = new UserProfile(token, user);
                userManager.saveProfile(token, p);
                userManager.saveProfile(user.getTicket(), p);

                logger.debug("用户{}已经验证通过。", user.getUsername());
                // 写入 token
                printCookie(rep, tokenParameterName, token);
                logger.debug("token 写入cookie成功。");
                req.getSession().setAttribute("user", user);

                Map<String, String> msg = new HashMap<>();
                msg.put("redirect", service);
                resultMap.put("userInfo",user);
                resultMap.put("msg",msg);
                logger.info("用户{}登录成功！", user.getUsername());
            }
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, resultMap);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 退出
     *
     * @return json
     */
    @RequestMapping(value = "logusers/logout")
    @ResponseBody
    public ResponseEntity<String> logout(HttpServletRequest req, HttpServletResponse rep) {
        ErrorType errorType = null;
        try {
            //清空 cookie
            printCookie(rep, tokenParameterName, null);
            req.logout();
        } catch (Exception e) {
            logger.error("x",e);
            errorType = ErrorType.User_Logout_Error;
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, null);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 注册
     *
     * @param param
     * @return result
     */
    @RequestMapping(value = "login/register", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<String> register(String param) {
        User user = JSON.parseObject(param, User.class);
        User userDb = null;
        ErrorType errorType = null;
        if (StringUtils.hasText(user.getUsername())) {
            userDb = userManager.findByUsername(user.getUsername());
        }
        if (StringUtils.hasText(user.getEmail())) {
            userDb = userManager.findByEmail(user.getEmail());
        }

        if(userDb != null){
            errorType = ErrorType.User_Exists_Error;
        }else{
            String invitationCode = user.getInvitationCode();
            if (StringUtil.isNotEmpty(invitationCode)) {
                InvitationCode invitationCodeObj = userManager.getInvitationCode(user.getInvitationCode());
                if (invitationCodeObj != null) {
                    //查询当前企业剩余可以添加的用户数量count，满足limit-count>num才行。
                    String roles = ConfigCentre.getString(ConfigConst.MANAGE_USER_LIMIT_ROLES);
                    int count  = userManager.checkLimitNumForGenerateInvitation(invitationCodeObj.getOrgId(),roles);
                    int left = ConfigCentre.getInteger(ConfigConst.MANAGE_USER_MAX) - count;
                    if(left < 1){
                        //当用户达到上限
                        errorType = ErrorType.User_Register_Limit;
                    }else{

                        user.setOrgId(invitationCodeObj.getOrgId());
                        //user.setRoleId(invitationCodeObj.getRoleId());
                        user.setInvitationCode(invitationCode);
                        String password = new Md5Hash(user.getPassword(), user.getUsername() + user.getSalt()).toString();
                        user.setPassword(password);
                        user.setTicket(UUID.randomUUID().toString());
                        user.setLocked(Boolean.FALSE);
                        user.setStatus(0);
                        user.setUpdateTime(new Date().getTime());
                        try {
                            userManager.save(user, invitationCodeObj.getRoleId(), invitationCodeObj.getId());
                        } catch (Exception e) {
                            //Add by evan失败了得把验证码重置为可用
                            userManager.updateInvitaionCodeStatus(invitationCodeObj.getId(), InvitaionCodeStatus.VALID);
                            logger.error("x", e);
                            errorType = ErrorType.User_Register_Error;
                        }
                    }
                } else {
                    errorType = ErrorType.User_Invitaion_Code_Error;
                }
            } else {
                errorType = ErrorType.User_Invitaion_Code_Error;
            }
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, null);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 查找用户
     * 输入一个参数即可，如果都设置，默认用username
     *
     * @param param 用户名
     * @return json
     */
    @RequestMapping(value = "login/find")
    @ResponseBody
    public ResponseEntity<String> find(String param) {
        User user = null;
        ErrorType errorType = null;
        User resultUser = null;
        Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
        String username = paramMap.get("username");
        String email = paramMap.get("email");
        if (StringUtils.hasText(username)) {
            user = userManager.findByUsername(username);
        }
        if (StringUtils.hasText(email)) {
            user = userManager.findByEmail(email);
        }
        RespModel result;
        if (user == null) {
            errorType = ErrorType.User_Exists_Error;
        } else {
            resultUser = new User();
            BeanUtils.copyProperties(user,resultUser);
            resultUser.setId(null);
            resultUser.setPassword(null);
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, resultUser);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 验证邀请码
     *
     * @param param
     * @return
     */
    @RequestMapping(value = "login/validateInvitationCode")
    @ResponseBody
    public ResponseEntity<String> validateInvitationCode(String param) {
        Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
        String invitationCode = paramMap.get("invitationCode");
        InvitationCode invitationCodeObj = null;
        ErrorType errorType = null;
        if (StringUtils.hasText(invitationCode)) {
            invitationCodeObj = userManager.getInvitationCode(invitationCode);
        }

        if (invitationCodeObj == null) {
            errorType = ErrorType.User_Invitaion_Code_Error;
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, null);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 根据登录用户获取菜单树
     * @param req
     * @return
     */
    @RequestMapping(value = "user/getMenu")
    @ResponseBody
    public ResponseEntity<String> getMenuList(HttpServletRequest req) {
        List<MenuVo> result = null;
        ErrorType errorType = null;
        User user = getUserByToken(req);
        List<MenuVo> menuVos = new ArrayList<>();
        if (user != null) {
            List<Long> roleIds = userManager.getRoleByUser(user.getId());
            List<Menu> menus = userManager.getMenuTreeByRoleWithLanguage(roleIds, -1l,user.getLanguage());
            if(menus !=null && menus.size() >0){
                //按照sort进行排序
                Collections.sort(menus);
                for(Menu menu:menus){
                    MenuVo menuVo= MenuToMenuVo(menu);
                    menuVo.setSon(getSonByMenuVo(roleIds, menuVo,user.getLanguage()));
                    menuVos.add(menuVo);
                }
            }
            //对menu进行排序，由于增加了
            result = menuVos;
        } else {
            errorType = ErrorType.INVALID_TOKEN;
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, result);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }
    private List<MenuVo> getSonByMenuVo(List<Long> roleIds,MenuVo menuVo,String lan){
    	List<MenuVo> menuVos = new ArrayList<>();
    	List<Menu> menus = userManager.getMenuTreeByRoleWithLanguage(roleIds, menuVo.getKey(),lan);
        if(menus !=null&& menus.size() >0){
            Collections.sort(menus);
            for(Menu menu:menus){
                MenuVo menuVo1= MenuToMenuVo(menu);
                List<MenuVo> son = getSonByMenuVo(roleIds,menuVo1,lan);
                if(!CollectionUtils.isEmpty(son)){
                	menuVo1.setSon(son);
                }
                menuVos.add(menuVo1);
            }
        }
		return menuVos;
    }
    private MenuVo MenuToMenuVo(Menu menu){
    	MenuVo menuVo= new MenuVo();
        menuVo.setKey(menu.getId());
        menuVo.setIcon(menu.getIcon());
        menuVo.setUrl(menu.getWidget());
        menuVo.setValue(menu.getName());
        return menuVo;
    }
    /**
     * 当前用户
     * @param req
     * @return
     */
    @RequestMapping(value = "user/current")
    @ResponseBody
    public ResponseEntity<String> getCurrent(HttpServletRequest req) {
        User result = null;
        ErrorType errorType = null;
        User user = (User) req.getSession().getAttribute("user");
        if (user == null) {
            errorType = ErrorType.User_Not_Exists;
        } else {
            result = new User();
            BeanUtils.copyProperties(user,result);
            result.setId(null);
            result.setPassword(null);
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, result);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 当前FB用户
     * @param req
     * @return
     */
    @RequestMapping(value = "user/currentFbUser")
    @ResponseBody
    public ResponseEntity<String>  getCurrentFbUser(HttpServletRequest req) {
        ErrorType errorType = null;
        FbUser result = null;
        User user = (User) req.getSession().getAttribute("user");
        if (user == null) {
            errorType = ErrorType.User_Not_Exists;
        } else {
            result = userManager.getFbUserByUserId(user.getTicket());
            if(result == null){
                errorType = ErrorType.User_Not_Has_Facebook_User;
            }
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, result);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 解绑FB用户
     * @param param
     * @param req
     * @return
     */
    @RequestMapping(value = "user/unbindFbUser")
    @ResponseBody
    public ResponseEntity<String>  unBindFbUser(String param,HttpServletRequest req) {
        ErrorType errorType = null;
        FbUser result = null;
        User user = (User) req.getSession().getAttribute("user");
        if (user == null) {
            errorType = ErrorType.User_Not_Exists;
        } else {
            Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
            String password = paramMap.get("password");
            String passwordHash = new Md5Hash(password, user.getUsername() + user.getSalt()).toString();
            if (!passwordHash.equals(user.getPassword())) {
                errorType = ErrorType.User_Passowrd_Error;
            } else {
                result = userManager.getFbUserByUserId(user.getTicket());
                if(result == null){
                    errorType = ErrorType.User_Not_Has_Facebook_User;
                }else{
                    userManager.unBindFbUser(result.getFbUserId());
                }
            }
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, result);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 忘记密码
     * 申请重置，发送重置邮件到用户邮箱
     *
     * @param param
     * @return json
     */
    @RequestMapping(value = "login/doforget")
    @ResponseBody
    public ResponseEntity<String>  forgetPassword(String param) {
        ErrorType errorType = null;
        Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
        String email = paramMap.get("email");
        if (email == null) {
            errorType = ErrorType.User_Email_Has_Null_Error;
        } else {
            User user = userManager.findByEmail(email.trim());
            if (null == user) {
                errorType = ErrorType.User_Email_Has_Error;
            } else {
                boolean flag = false;
                try {
                    flag = userManager.forget(user);
                } catch (Exception e) {
                    errorType = ErrorType.INTERNAL_EXCEPTION;
                }
                if (!flag) {
                    errorType = ErrorType.User_Email_Has_Send_Error;
                }
            }
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, null);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 用户设置
     *
     * @param param
     * @return
     */
    @RequestMapping(value = "user/edit")
    @ResponseBody
    public ResponseEntity<String> edit(String param, HttpServletRequest req, HttpServletResponse resp) {
        ErrorType errorType = null;
        User seUser = getUserByToken(req);
        User db = getUser(seUser.getUsername());
        if (db == null) {
            errorType = ErrorType.INVALID_TOKEN;
        } else {
            Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
            //这里不改 用户名和邮箱
            db.setNickname(paramMap.get("nickname"));
            db.setCountry(paramMap.get("country"));
            db.setTimezoneId(paramMap.get("timezoneId"));
            db.setTimezoneName(paramMap.get("timezoneName"));
            db.setLanguage(paramMap.get("language"));
            db.setUpdateTime(new Date().getTime());
            try {
                userManager.update(db);
                req.getSession().setAttribute("user", db); // 刷新 session

            } catch (Exception e) {
                logger.error("x", e);
                errorType = ErrorType.INTERNAL_EXCEPTION;
            }
            // 修改后退出，需要重新登录
            logout(req, resp);
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, null);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 修改密码
     *
     * @param param
     * @param req
     * @param resp
     * @return
     */
    @RequestMapping(value = "user/chgpwd")
    @ResponseBody
    public ResponseEntity<String> chgpwd(String param, HttpServletRequest req, HttpServletResponse resp) {
        ErrorType errorType = null;
        User seUser = getUserByToken(req);
        User db = getUser(seUser.getUsername());
        if (db == null) {
            errorType = ErrorType.INVALID_TOKEN;
        } else {
            Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
            String oldPassword = paramMap.get("oldPassword");
            String password = paramMap.get("password");
            String oldPasswordHash = new Md5Hash(oldPassword, db.getUsername() + db.getSalt()).toString();
            if (!oldPasswordHash.equals(db.getPassword())) {
                errorType = ErrorType.User_Passowrd_Error;
            } else {
                String newPasswordHash = new Md5Hash(password, db.getUsername() + db.getSalt()).toString();
                //这里不改 用户名和邮箱
                db.setPassword(newPasswordHash);
                db.setUpdateTime(new Date().getTime());
                try {
                    userManager.update(db);
                } catch (Exception e) {
                    logger.error("x", e);
                    errorType = ErrorType.INTERNAL_EXCEPTION;
                }
                // 修改后退出，需要重新登录
                logout(req, resp);
            }
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, null);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 根据用户名或者邮箱查询用户。
     * @param param
     * @param req
     * @return
     */
    @RequestMapping(value = "user/findByUsernameOrEmail")
    @ResponseBody
    public ResponseEntity<String> findByUsernameOrEmail(String param, HttpServletRequest req) {
        ErrorType errorType = null;
        User seUser = getUserByToken(req);
        Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
        String usernameOrEmailStr = paramMap.get("usernameOrEmailStr");
        List<User>  list = userManager.findByUsernameOrEmail(usernameOrEmailStr,seUser.getTicket(),seUser.getOrgId());
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, list);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }


    /**
     * 注销用户
     * @param param
     * @param req
     * @return
     */
     @RequestMapping(value = "user/delete")
     @ResponseBody
     public ResponseEntity<String> delete(String param, HttpServletRequest req) {
         ErrorType errorType = null;
         Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
         String userId = paramMap.get("userId");
         userManager.deleteUser(Long.parseLong(userId));
         OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, null);
         return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
     }

    /**
     * 生成注册码
     * @param param
     * @return
     */
    @RequestMapping(value = "user/generateRegisterCode")
    @ResponseBody
    public ResponseEntity<String> generateRegisterCode( HttpServletRequest req,String param) {
        Map<String, String> paramMap = StringUtil.parseParamsToMap(param);
        User seUser = getUserByToken(req);
        String roleStr = paramMap.get("roleId");
        String numStr = paramMap.get("num");
        Long roleId = Long.parseLong(roleStr);
        Integer num = Integer.parseInt(numStr);
        List<InvitationCode> result = null;
        ErrorType errorType = null;
        OutputResult outputResult;
        try {
            //查询当前企业剩余可以添加的用户数量count，满足limit-count>num才行。
            String roles = ConfigCentre.getString(ConfigConst.MANAGE_USER_LIMIT_ROLES);
            int count  = userManager.checkLimitNumForGenerateInvitation(seUser.getOrgId(),roles);
            int left = ConfigCentre.getInteger(ConfigConst.MANAGE_USER_MAX) - count;
            if(left < num){
                errorType = ErrorType.User_Manage_Limit;
                outputResult = ResponseUtils.bulidOutputResultWithPlaceholders(errorType, result, left);
            }else{
                result = userManager.generateInvitation(seUser.getOrgId(), roleId, num);
                outputResult = ResponseUtils.bulidOutputResult(errorType, result);
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            errorType = ErrorType.INTERNAL_EXCEPTION;
            outputResult = ResponseUtils.bulidOutputResult(errorType, result);
        }
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }




    private User getUserByToken(HttpServletRequest req) {
        return (User) req.getSession().getAttribute("user");
    }

    /**
     * 根据用户名或邮箱获取用户
     *
     * @param name username or email
     * @return user
     */
    private User getUser(String name) {
        if (!StringUtils.hasText(name)) return null;
        //if email
        if (name.contains("@")) {
            return userManager.findByEmail(name);
        } else {
            return userManager.findByUsername(name);
        }
    }

    private void printCookie(HttpServletResponse rep, String name, String value) {
        Cookie cookie = new Cookie(name, value);
        cookie.setPath("/");
        cookie.setDomain(ConfigCentre.getString("masterDomain"));
        rep.addCookie(cookie);
    }

    /**
     * 生成token的算法
     *
     * @return uuid token
     */
    private String generateToken() {
        return UUID.randomUUID().toString();
    }




}
